package org.geekforum.config;

import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.*;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.*;

import static java.util.Collections.singletonList;

/**
 * 专业的GeekForum API Swagger配置
 * <p>
 * 功能特性:
 * - 全面的API文档
 * - 专业的样式和品牌展示
 * - 安全方案集成
 * - 有序的API分组
 *
 * @author ZJx
 * @version 2.0
 * @since 2025
 */
@Configuration
@EnableOpenApi
public class SwaggerConfig {

    /**
     * 主要API文档配置
     *
     * @return 配置了专业设置的Docket
     */
    @Bean
    public Docket createApi() {
        return new Docket(DocumentationType.OAS_30)
                .groupName("GeekForum-API-v2.0")
                .apiInfo(buildApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("org.geekforum.controller"))
                .paths(PathSelectors.regex("/(?!error).*"))
                .build()
                .protocols(newHashSet("http", "https"))
                .securitySchemes(singletonList(apiKey()))
                .securityContexts(singletonList(securityContext()))
                .tags(
                        new Tag("用户管理", "用户注册、认证和个人资料管理"),
                        new Tag("文章管理", "论坛文章和帖子操作"),
                        new Tag("版块管理", "讨论版块分类和导航"),
                        new Tag("回复管理", "文章回复和评论系统"),
                        new Tag("消息系统", "私信和通知功能"),
                        new Tag("系统管理", "系统测试和管理功能")
                );
    }

    /**
     * 专业的API信息配置
     */
    private ApiInfo buildApiInfo() {
        return new ApiInfoBuilder()
                .title("🚀 GeekForum API文档")
                .description(buildApiDescription())
                .contact(new Contact(
                        "SuperZ",
                        "https://github.com/geekforum-project",
                        "contact@geekforum.dev"
                ))
                .license("MIT许可证")
                .licenseUrl("https://opensource.org/licenses/MIT")
                .termsOfServiceUrl("https://geekforum.dev/terms")
                .version("2.0.0")
                .build();
    }

    /**
     * 构建全面的中文API描述
     */
    private String buildApiDescription() {
        return "<div style='font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif;'>" +
                "<h2>🎯 GeekForum - 专业技术讨论平台</h2>" +
                "<p><strong>基于Spring Boot和前沿技术构建的现代化、功能丰富的论坛系统。</strong></p>" +
                "<h3>🌟 核心功能:</h3>" +
                "<ul>" +
                "<li>🔐 <strong>安全认证</strong> - 基于会话的用户管理和基于角色的访问控制</li>" +
                "<li>📝 <strong>富内容管理</strong> - 创建、编辑和管理论坛文章，支持高级编辑功能</li>" +
                "<li>💬 <strong>互动讨论</strong> - 实时回复和多层级对话</li>" +
                "<li>📋 <strong>有序版块</strong> - 分类讨论区域，更好的内容组织</li>" +
                "<li>📨 <strong>私信系统</strong> - 用户间安全的直接通信</li>" +
                "<li>🎨 <strong>现代UI/UX</strong> - 响应式设计，支持深色/浅色主题</li>" +
                "</ul>" +
                "<h3>🔧 技术栈:</h3>" +
                "<ul>" +
                "<li><strong>后端:</strong> Spring Boot 2.7.6, MyBatis, MySQL, Druid连接池</li>" +
                "<li><strong>前端:</strong> 现代JavaScript, Bootstrap, 响应式设计</li>" +
                "<li><strong>文档:</strong> OpenAPI 3.0 with Swagger UI</li>" +
                "<li><strong>架构:</strong> RESTFUL API, MVC模式, 分层架构</li>" +
                "</ul>" +
                "<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 8px; margin: 15px 0;'>" +
                "<strong>💡 专业提示:</strong> 使用'试一试'功能直接测试API端点。" +
                "大多数端点需要认证 - 请查看下面的安全方案。" +
                "</div>" +
                "</div>";
    }

    /**
     * API文档安全配置
     */
    private ApiKey apiKey() {
        return new ApiKey("sessionId", "JSESSIONID", "cookie");
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/(?!auth).*"))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return singletonList(new SecurityReference("sessionId", authorizationScopes));
    }

    @SafeVarargs
    private static <T> Set<T> newHashSet(T... ts) {
        if (ts.length > 0) {
            return new LinkedHashSet<>(Arrays.asList(ts));
        }
        return null;
    }

    /**
     * Spring Boot Actuator兼容性配置
     * 解决SpringBoot 2.6+和Swagger 3.0兼容性问题
     */
    @Bean
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
                                                                         ServletEndpointsSupplier servletEndpointsSupplier,
                                                                         ControllerEndpointsSupplier controllerEndpointsSupplier,
                                                                         EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
                                                                         WebEndpointProperties webEndpointProperties, Environment environment) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        String basePath = webEndpointProperties.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment,
                basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
                corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
                shouldRegisterLinksMapping, null);
    }

    private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
                                               String basePath) {
        return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
                || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
    }

}

